package cn.suimg.neo4j.config;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;
import java.util.Arrays;

/**
 * Redis缓存配置
 */
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {

    @Bean
    @ConfigurationProperties(prefix = "spring.redis.config")
    public JedisPoolConfig getJedisPoolConfig(){
        return new JedisPoolConfig();
    }

    @Bean
    public JedisPool getJedisPool(JedisPoolConfig config, @Value("${spring.redis.host}") String host, @Value("${spring.redis.port}") Integer port, @Value("${spring.redis.password}") String password){
        if(StringUtils.isBlank(password))
            return new JedisPool(config,host,port);
        return new JedisPool(config,host,port,60,password);
    }


    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        // 因为每步会生成新的对象，所以必须链式调用
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(30))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .disableKeyPrefix()
                .disableCachingNullValues();

        // 创建无锁的RedisCacheWriter
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(factory);
        return RedisCacheManager.builder(redisCacheWriter).cacheDefaults(redisCacheConfiguration).build();
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        return new RedisTemplate<String, Object>(){{
            setConnectionFactory(factory);
            setKeySerializer(new StringRedisSerializer());
            setValueSerializer(new GenericJackson2JsonRedisSerializer());
            setHashKeySerializer(new StringRedisSerializer());
            setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        }};
    }

    /**
     * 使用@Cacheable注解自动缓存的Key生成策略
     * @return
     */
    @Override
    public KeyGenerator keyGenerator() {
        return (object, method, params) -> {
            StringBuilder cacheKey = new StringBuilder();
            cacheKey.append(object.getClass().getName().replaceAll("\\.",":"));
            cacheKey.append(":");
            cacheKey.append(method.getName());
            cacheKey.append(":");
            Arrays.stream(params).forEach(param -> cacheKey.append(param).append(","));
            return cacheKey.substring(0,cacheKey.length() -1);
        };
    }
}
